using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data.Common;
using System.Globalization;
using System.Collections;

public partial class Applications : System.Web.UI.Page
//TODO: Add custom validator for bundles, .net, java must contain at least one
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Page.ClientScript.RegisterClientScriptInclude("main", ResolveUrl("~/js/main.js"));
        if(!Page.IsPostBack) {
            mltMain.ActiveViewIndex = 0;
            if(grdApplications.Rows.Count == 0) {
                grdApplications.GridLines = GridLines.None;
            }
        }
        Master.RenderJSArrayWithCliendIds(cboDefaultLanguage, cboAppType, lstAvailableLangs, lstSelectedLangs, lstBundles, txtNewBundle);
        Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "checkAllLanguages", @"
        function checkAllLanguages() {
            var selectedlanguages = document.getElementById(GetClientId('lstSelectedLangs'));
            for(var i=0;i<selectedlanguages.length;i++) {
                selectedlanguages.options[i].selected = true;
            }
            var selectedBundles = document.getElementById(GetClientId('lstBundles'));
            for(var i=0;i<selectedBundles.length;i++) {
                selectedBundles.options[i].selected = true;
            }
        }
        ", true);
    }

    protected void grdApplications_RowCommand(object sender, GridViewCommandEventArgs e) {
        Database db = new Database();
        switch(e.CommandName) {
            case "edit":
                mltMain.ActiveViewIndex = 1;
                using(Database.Command cmd = db.CreateCommand()) {
                    db.OpenConnection();
                    cmd.CommandText = "SELECT * FROM applications WHERE id = @p";
                    cmd.AddParameterWithValue("@p", e.CommandArgument.ToString());
                    DbDataReader reader = cmd.ExecuteReader();
                    string defaultLanguage = string.Empty,
                           applicationType = string.Empty;
                    string[] selectedLanguages = null, 
                             bundles = null;
                    while(reader.Read()) {
                        txtAppName.Text = reader["name"].ToString();
                        txtDisplayName.Text = reader["displayname"].ToString();
                        applicationType = reader["type"].ToString();
                        defaultLanguage = reader["defaultlanguage"].ToString();
                        selectedLanguages = reader["languages"].ToString().Split(',');
                        bundles = reader["bundles"].ToString().Split(',');
                        hidApplicationId.Value = reader["id"].ToString();
                        Page.Title = "Editing " + txtDisplayName.Text+" &raquo; ResourceBlender";
                    }
                    reader.Close();
                    BindComboOptions(selectedLanguages, defaultLanguage, applicationType, bundles);
                }
                break;
            case "confirmdelete":
                mltMain.ActiveViewIndex = 2;
                hidApplicationIdDelete.Value = e.CommandArgument.ToString();
                using(Database.Command cmd = db.CreateCommand()) {
                    db.OpenConnection();
                    cmd.CommandText = "SELECT displayname FROM applications WHERE id = @p";
                    cmd.AddParameterWithValue("@p", e.CommandArgument.ToString());
                    DbDataReader reader = cmd.ExecuteReader();
                    while(reader.Read()) {
                        lblConfirmDelete.Text = string.Format("Are you sure you want to delete the application <em>{0}</em> from the database?", reader.GetString(0));
                    }
                    reader.Close();
                }
                break;
            default:
                mltMain.ActiveViewIndex = 0;
                break;
        }
        db.CloseConnection();
    }

    #region Adding/Editing
    /// <summary>
    /// Populates the 'Application Type', 'Bundles' and language combo boxes
    /// </summary>
    /// <param name="selectedLanguages">The languages included in the application.</param>
    /// <param name="defaultLanguage">The default language.</param>
    /// <param name="applicationType">Type of the application.</param>
    private void BindComboOptions(string[] selectedLanguages, string defaultLanguage, string applicationType, string[] bundles) {
        CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
        List<ListItem> availableCultures = new List<ListItem>(),
                       selectedCultures = new List<ListItem>(),
                       bundleList = new List<ListItem>();
        foreach(CultureInfo culture in cultures) {
            if(culture.Name.Length > 0) {
                if(selectedLanguages.Contains(culture.Name)) {
                    ListItem itm = new ListItem(culture.EnglishName, culture.Name);
                    selectedCultures.Add(itm);
                } else {
                    availableCultures.Add(new ListItem(culture.EnglishName, culture.Name));
                }
            }
        }
        ListComparer comp = new ListComparer();
        availableCultures.Sort(comp);
        selectedCultures.Sort(comp);
        lstAvailableLangs.Items.AddRange(availableCultures.ToArray());
        lstSelectedLangs.Items.AddRange(selectedCultures.ToArray());
        cboDefaultLanguage.Items.AddRange(selectedCultures.ToArray());
        cboDefaultLanguage.SelectedValue = defaultLanguage;
        cboAppType.DataSource = EnumBinder.EnumHelper.ToList(typeof(Constants.ResourceType));
        cboAppType.DataTextField = "Value";
        cboAppType.DataValueField = "Key";
        cboAppType.DataBind();
        if(!String.IsNullOrEmpty(applicationType)) {
            cboAppType.SelectedValue = applicationType;
        }
        foreach(string bundle in bundles) {
            if(bundle.Trim().Length > 0) {
                bundleList.Add(new ListItem(bundle, bundle)); // todo: bundleId as value?
            }
        }
        bundleList.Sort(comp);
        foreach(ListItem itm in bundleList) {
            lstBundles.Items.Add(itm);
        }
    }

    /// <summary>
    /// Shows a form to add a new application/
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void lnkAddApplication_Click(object sender, EventArgs e) {
        mltMain.ActiveViewIndex = 1;
        Page.Title = "Add Application &raquo; ResourceBlender";
        BindComboOptions(new string[]{}, "", "", new string[]{});
    }

    /// <summary>
    /// Validates one or more languages are selected.
    /// </summary>
    /// <param name="source">The source.</param>
    /// <param name="args">The <see cref="System.Web.UI.WebControls.ServerValidateEventArgs"/> instance containing the event data.</param>
    protected void validateHasLanguages(object source, ServerValidateEventArgs args) {
        args.IsValid = false;
        foreach(string key in Request.Form.AllKeys) {
            if(key.Contains(lstSelectedLangs.ID)) {
                string langs = Request.Form[key];
                if(langs.Split(',').Length > 0) { 
                    args.IsValid = true;
                }
                break;
            }
        }
    }

    /// <summary>
    /// Moves a language from 'Selected languages' to 'Available languages'
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnRemoveLang_Click(object sender, EventArgs e) {
        ListItem item = lstSelectedLangs.SelectedItem;
        if(item != null) {
            item.Selected = false;
            lstSelectedLangs.Items.Remove(item);
            ListItem[] items = new ListItem[lstAvailableLangs.Items.Count + 1];
            items[0] = item;
            lstAvailableLangs.Items.CopyTo(items, 1);
            Array.Sort(items, new ListComparer());
            lstAvailableLangs.Items.Clear();
            lstAvailableLangs.Items.AddRange(items);
            cboDefaultLanguage.Items.Remove(item);
        }
    }

    /// <summary>
    /// Moves a language from 'Available languages' to 'Selected languages'
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnAddLang_Click(object sender, EventArgs e) {
        ListItem item = lstAvailableLangs.SelectedItem;
        if(item == null) {
            return;
        }
        item.Selected = false; // deselect the item - only one item can be selected
        lstAvailableLangs.Items.Remove(item);
        ListItem[] items = new ListItem[lstSelectedLangs.Items.Count + 1];
        items[0] = item;
        lstSelectedLangs.Items.CopyTo(items, 1);
        Array.Sort(items, new ListComparer());
        lstSelectedLangs.Items.Clear();
        lstSelectedLangs.Items.AddRange(items);
        cboDefaultLanguage.Items.Clear();
        cboDefaultLanguage.Items.AddRange(items);
    }

    /// <summary>
    /// Removes the selected bundles
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnRemoveBundle_Click(object sender, EventArgs e) {
        if(lstBundles.SelectedIndex >= 0) {
            for(int i=lstBundles.Items.Count-1;i>=0;i--) {
                ListItem itm = lstBundles.Items[i];
                if(itm.Selected) {
                    lstBundles.Items.RemoveAt(i);
                }
            }
        }
    }
    /// <summary>
    /// Adds a new bundle
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnAddBundle_Click(object sender, EventArgs e) {
        string bundle = txtNewBundle.Text.Trim();
        if(bundle.Length > 0) {
            bool exists = false;
            for(int i = 0; i < lstBundles.Items.Count; i++) {
                if(lstBundles.Items[i].Text.Equals(bundle, StringComparison.InvariantCultureIgnoreCase)) {
                    exists = true;
                    break;
                }
            }
            if(!exists) {
                lstBundles.Items.Add(bundle);
            }
        }
    }

    /// <summary>
    /// Saves or adds the application.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnSave_Click(object sender, EventArgs e) {
        Page.Validate("vldLanguages");
        if(Page.IsValid) {
            Database db = new Database();
            db.OpenConnection();
            using(Database.Command cmd = db.CreateCommand()) {
                switch(hidApplicationId.Value) {
                    case "add":
                        cmd.CommandText = "INSERT INTO applications (displayname, name, id, type, defaultlanguage, languages, bundles) VALUES (@displayname, @name, @id, @type, @defaultlanguage, @languages, @bundles)";
                        cmd.AddParameterWithValue("@id", Utils.GenID(true));
                        break;
                    default:
                        cmd.CommandText = "UPDATE applications SET displayname = @displayname, name = @name, type = @type, defaultlanguage = @defaultlanguage, languages = @languages, bundles = @bundles WHERE id = @id";
                        cmd.AddParameterWithValue("@id", hidApplicationId.Value);
                        break;
                }
                cmd.AddParameterWithValue("@displayname", txtDisplayName.Text);
                cmd.AddParameterWithValue("@name", txtAppName.Text);
                cmd.AddParameterWithValue("@type", cboAppType.SelectedValue);
                string selectedLanguages = string.Empty,
                       defaultLanguages = string.Empty,
                       bundles = string.Empty;
                foreach(string key in Request.Form.AllKeys) {
                    if(key.Contains(lstSelectedLangs.ID)) {
                        selectedLanguages = Request.Form[key];
                    } else if(key.Contains(cboDefaultLanguage.ID)) {
                        defaultLanguages = Request.Form[key];
                    } else if(key.Contains(lstBundles.ID)) {
                        bundles = Request.Form[key];
                    }
                }
                cmd.AddParameterWithValue("@defaultlanguage", defaultLanguages);
                cmd.AddParameterWithValue("@languages", selectedLanguages);
                cmd.AddParameterWithValue("@bundles", bundles);
                cmd.ExecuteNonQuery();
            }
            db.CloseConnection();
            Response.Redirect("~/Applications.aspx");
        }
    }
    #endregion

    #region Deleting
    /// <summary>
    /// Confirms deletion of a application and removes it from the database.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnOk_Click(object sender, EventArgs e) {
        Database db = new Database();
        db.OpenConnection();
        using(Database.Command cmd = db.CreateCommand()) {
            cmd.CommandText = "DELETE FROM applications WHERE id = @p";
            cmd.AddParameterWithValue("@p", hidApplicationIdDelete.Value);
            cmd.ExecuteNonQuery();
        }
        db.CloseConnection();
        Response.Redirect("~/Applications.aspx");
    }
    
    /// <summary>
    /// Redirects the user to the 'Manage applications' page.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void btnCancelDelete_Click(object sender, EventArgs e) {
        Response.Redirect("~/Applications.aspx");
    }
    #endregion

}
